package gang.org.springframework.framework.metadata;

import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Iterator;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

final class GangMergedAnnotationsCollection implements GangMergedAnnotations{

    /**
     * 业务意义
     * GangMergedAnnotation 用于存储注解实例 E.g GConfiguration
     * */
    private final GangMergedAnnotation<?> [] annotations;

    private final GangAnnotationTypeMappings[] mappings;

    public GangMergedAnnotationsCollection(GangMergedAnnotation<?>[] annotations, GangAnnotationTypeMappings[] mappings) {
        this.annotations = annotations;
        this.mappings = mappings;
    }

    /**
     * TODO 业务意义？
     * GangMergedAnnotationsCollection 注解类的集合
     * @param annotations 注解类类 E.g gang.org.springframework.framework.annotation.GConfiguration
     * */
    private GangMergedAnnotationsCollection(Collection<GangMergedAnnotation<?>> annotations){
        this.annotations = annotations.toArray(new GangMergedAnnotation<?>[0]);
        /**
         * >GangMergedAnnotationsCollection.java
         *  >attr:mappings[6]第二层
         * */
        this.mappings = new GangAnnotationTypeMappings[this.annotations.length];
        for (int i = 0; i < this.annotations.length; i++) {
            GangMergedAnnotation<?> annotation = this.annotations[i];
            /**
             * >GangMergedAnnotationsCollection.java
             *  >attr:mappings[6]
             *      >attr:mappings[1] 第三层
             * */
            this.mappings[i] = GangAnnotationTypeMappings.forAnnotationType(annotation.getType());
        }
    }

    /**
     * 业务意义：解析class类有两类
     * 1）一类是springboot内部类, 例如：GangConfigurationClassParser.java
     * 2) 二类是spring.factories, 例如：GangServletWebServerFactoryAutoConfiguration.java
     * 2.1 获取配置类中的注解 @GImport
     *
     * 业务意义：解析class对象结构
     * 1）SpringBoot资源配置文件类，ServletWebServerFactoryAutoConfiguration -> SourceClass -> SimpleAnnotationMetadata -> MergedAnnotationsCollection
     * 2) SpringBoot内置文件类， ConfigurationPostProcessor -> SourceClass -> StandardAnnotationMetadata - > TypeMappedAnnotations
     * */
    @Override
    public <A extends Annotation> GangMergedAnnotation get(String annotationType, Predicate<? super GangMergedAnnotation<A>> predicate, GangMergedAnnotationSelector<A> selector) {

        GangMergedAnnotation<A> result = find(annotationType, predicate, selector);

        return result != null ? result : GangMergedAnnotation.missing();
    }
    
    
    /**
     * 业务意义
     * 1）配置对象 ServletWebServerFactoryAutoConfiguration-> SourceClass -> SimpleAnnotationMetadata -> MergedAnnotationsCollection 注解进行处理
     * */
    private <A extends Annotation> GangMergedAnnotation<A> find(Object requireType, Predicate<? super GangMergedAnnotation<A>> predicate, GangMergedAnnotationSelector<A> selector) {

        if (selector == null) {
            //TODO
        }
        
        GangMergedAnnotation<A> result = null;


        for (int i = 0; i < this.annotations.length; i++) {
            /**
             * 数据结构
             * 1）SourceClass = ServletWebServerFactoryAutoConfiguration 配置类
             * 2) MergedAnnotationsCollection -> annotations = { @AutoConfiguration, @AutoConfigureOrder, @ConditionalOnClass, @ConditionalOnWebApplication, @EnableConfigurationProperties, @Import}
             * 3) MergedAnnotationsCollection -> annotation = {
             *     mapping = AutoConfiguration
             *     source = ServletWebServerFactoryAutoConfiguration
             * }
             * */
            GangMergedAnnotation<?> root = this.annotations[i];

            /**
             * 数据结构
             * this.mappings = {
             *     0:AutoConfiguration
             *     1:Configuration
             *     2:AutoConfigureBefore
             *     3:AutoConfigureAfter
             *     4:Component
             *     5:Index
             * }
             * */
            GangAnnotationTypeMappings mappings = this.mappings[i];

            for (int mappingIndex = 0 ; mappingIndex < mappings.size(); mappingIndex++) {

                GangAnnotationTypeMapping mapping = mappings.get(mappingIndex);

                if (!isMappingForType(mapping, requireType)) {
                    continue;
                }

                GangMergedAnnotation<A> candidate = mappingIndex == 0 ? (GangMergedAnnotation<A>) root : GangTypeMappedAnnotation.createIfPossible(mapping, root, null);

                if (candidate != null && (predicate == null || predicate.test(candidate))) {

                    if (selector.isBestCandidate(candidate)) {

                        return candidate;

                    }
                }
            }

        }
        
        return null;
    }

    /**
     * TODO 业务意义？
     * */
    @Override
    public Iterator<GangMergedAnnotation<Annotation>> iterator() {
        return null;
    }

    /**
     * 业务意义
     * @param annotations 传入注解类对象 E.g gang.org.springframework.framework.annotation.GConfiguration
     * */
    static GangMergedAnnotations of(Collection<GangMergedAnnotation<?>> annotations){
        if (annotations.isEmpty()) {
            return GangTypeMappedAnnotations.NONE;
        }
        return new GangMergedAnnotationsCollection(annotations);
    }

    @Override
    public boolean isPresent(String annotationType) {
        return isPresent(annotationType, false);
    }

    /**
     * 业务意义
     * @param requiredType 可以有多个业务含义
     *                     场景一 传指定注解类全路径名 gang.org.springframework.framework.annotation.GConfiguration
     * */
    private boolean isPresent(Object requiredType, boolean directOnly){
        for (GangMergedAnnotation<?> annotation : this.annotations) {
            Class<?> type = annotation.getType();
            if(type == requiredType || type.getName().equals(requiredType)){
                return true;
            }
        }
        if (!directOnly){
            for (GangAnnotationTypeMappings mappings : this.mappings) {
                for (int i = 0; i < mappings.size(); i++) {
                    GangAnnotationTypeMapping mapping = mappings.get(i);
                    if (isMappingForType(mapping, requiredType)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * TODO 业务意义
     * */
    private static boolean isMappingForType(GangAnnotationTypeMapping mapping, Object requiredType){

        if (requiredType == null){
            return true;
        }

        Class<? extends Annotation> annotationType = mapping.getAnnotationType();
        return (annotationType == requiredType || annotationType.getName().equals(requiredType));
    }

    @Override
    public Stream<GangMergedAnnotation<Annotation>> stream() {
        return StreamSupport.stream(spliterator(),false);
    }

    @Override
    public Spliterator<GangMergedAnnotation<Annotation>> spliterator() {
        return spliterator(null);
    }

    private <A extends Annotation> Spliterator<GangMergedAnnotation<A>> spliterator(Object annotationType){
        return new GangAnnotationsSpliterator<>(annotationType);
    }

    private class GangAnnotationsSpliterator<A extends Annotation> implements Spliterator<GangMergedAnnotation<A>>{

        public Object requiredType;

        public final int[] mappingCursors;

        /**
         * 初始化参数
         * @param annotationType is null
         * */
        public GangAnnotationsSpliterator(Object annotationType) {

            //TODO
            this.mappingCursors = new int[annotations.length];
        }

        /**
         * ##################注：方法【tryAdvance】为一个循环方法##################
         *
         * 1）对自动化配置化类 ServletWebServerFactoryAutoConfiguration.java中的注解完成流化处理，重点处理该配置类中的注解
         * 2）AutoConfiguration， AutoConfigureOrder，ConditionalOnClass，ConditionalOnWebApplication，EnableConfigurationProperties，Import
         * */
        @Override
        public boolean tryAdvance(Consumer<? super GangMergedAnnotation<A>> action) {

            int lowestDistance = Integer.MAX_VALUE;
            int annotationResult = -1;

            for (int annotationIndex = 0; annotationIndex < annotations.length; annotationIndex ++)
            {
                GangAnnotationTypeMapping mapping = getNextSuitableMapping(annotationIndex);

                if (mapping != null) {
                    lowestDistance = 0;
                    annotationResult = annotationIndex;
                }



                //TODO
                break;
            }
            if (annotationResult != -1)
            {
                /**
                 * 业务意义每一个配置类例如：ServletWebServerFactoryAutoConfiguration.java 配置类，获取该配置类上所有的注解
                 * 1）AutoConfiguration
                 * 2）AutoConfigureOrder
                 * 3）ConditionalOnClass
                 * 4）ConditionalOnWebApplication
                 * 5）EnableConfigurationProperties
                 * 6）Import
                 *
                 * （注：注解对象，最终封装为 GangTypeMappedAnnotation）
                 * */
                GangMergedAnnotation<A> mergedAnnotation = createMergedAnnotationIfPossible(annotationResult, 0);
                this.mappingCursors[annotationResult] ++;

                if (mergedAnnotation == null) {
                    // TODO

                }


                action.accept(mergedAnnotation);

                return true;
            }

            return false;
        }

        @Deprecated
        private GangAnnotationTypeMapping getNextSuitableMapping(int annotationIndex)
        {
            GangAnnotationTypeMapping mapping;

            do {
                mapping = getMapping(annotationIndex, this.mappingCursors[annotationIndex]);

                if (mapping != null && isMappingForType(mapping, this.requiredType)) {
                    return mapping;
                }
                this.mappingCursors[annotationIndex] ++;
            }

            while (mapping != null);

            return null;
        }

        @Deprecated
        private GangAnnotationTypeMapping getMapping(int annotationIndex, int mappingIndex)
        {
            GangAnnotationTypeMappings mapping = GangMergedAnnotationsCollection.this.mappings[annotationIndex];
            return mappingIndex < mapping.size() ? mapping.get(mappingIndex) : null;
        }



        @Override
        public Spliterator<GangMergedAnnotation<A>> trySplit() {
            return null;
        }

        @Override
        public long estimateSize() {
            return 0;
        }

        @Override
        public int characteristics() {
            return NONNULL | IMMUTABLE;
        }

        /**
         * 业务意义，获取配置类中的注解，将其转为TypeMappedAnnotation
         * 1）例如配置类：ServletWebServerFactoryAutoConfiguration.java
         * 2) 注解 @AutoConfiguration @AutoConfigureOrder @ConditionalOnClass @ConditionalOnWebApplication @EnableConfigurationProperties Import
         * */
        public GangMergedAnnotation<A> createMergedAnnotationIfPossible(int annotationIndex, int mappingIndex)
        {
            GangMergedAnnotation<?> root = annotations[annotationIndex];

            if (mappingIndex == 0) {
                return (GangMergedAnnotation<A>) root;
            }

            //TODO
            //return GangTypeMappedAnnotation.createIfPossible();
            return null;
        }
    }


}
